package com.itCar.base.tools;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.DateFormat;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: DateUtil
 * @Description: TODO 时间日期工具
 * @author: liuzg
 * @Date: 2021/7/29 10:08
 * @Version: v1.0
 */
@Slf4j
public class DateUtil extends org.apache.commons.lang3.time.DateUtils {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前时间 + 输入的小时
     *
     * @param hourse
     * @return
     */
    public static String getDate(Integer hourse) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        // 24小时制
        cal.add(Calendar.HOUR, hourse);
        return sdf.format(cal.getTime());
    }

    /**
     * 根据传入的日期加天数
     *
     * @param date
     * @param day
     * @return
     */
    public static String addDate(String date, Integer day) {
        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(format.parse(date));
            cal.add(Calendar.DATE, day);
        } catch (ParseException e) {
            log.error(e.getMessage());
        }
        return format.format(cal.getTime());
    }


    /**
     * 将Date对象转换为指定格式的字符串
     *
     * @param date   Date对象
     * @param format 格式化字符串
     * @return Date对象的字符串表达形式
     */
    public static String formatDate(Date date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format(date);
    }

    /**
     * 根据日期获取星期
     * liuzhu
     */
    public static String getWeekOfDate(Date dt) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }

    public static String daysBetween(String startDate, String endDate) throws ParseException {
        long nd = 1000 * 24 * 60 * 60;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//设置时间格式
        Date newStartDate = sdf.parse(startDate);
        Date newEndDate = sdf.parse(endDate);
        long diff = (newEndDate.getTime()) - (newStartDate.getTime()); //计算出毫秒差
        // 计算差多少天
        String day = diff / nd + "";
        return day;
    }


    /**
     * 计算时间差
     *
     * @return
     */
    public static String getTimeDifference(String current, String last) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = null;
        java.util.Date date = null;
        try {
            now = df.parse(current);
            date = df.parse(last);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        long l = now.getTime() - date.getTime();
        long day = l / (24 * 60 * 60 * 1000);
        long hour = (l / (60 * 60 * 1000) - day * 24);
        long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);

        String differ = day + "天" + hour + "小时" + min + "分" + s + "秒";
//        System.out.println(differ);
        return differ;
    }

    /**
     * 根据传递时间加 1天
     *
     * @param time
     * @return
     */
    public static String getDateGal(String time) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date dd = df.parse(time);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dd);
            calendar.add(Calendar.DAY_OF_MONTH, 1);//加一天
            time = df.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return time;
    }

    /**
     * 将传递时间格式转换目标格式
     *
     * @param date
     * @param formatstring
     * @return
     */
    public static String getTimeByTransformation(Date date, String formatstring) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        SimpleDateFormat simpleFormat = new SimpleDateFormat(formatstring);
        return simpleFormat.format(cal.getTime());
    }

    /**
     * str类型时间转换date类型
     *
     * @param str
     * @param formatstring
     * @return
     */
    public static Date StrToDate(String str, String formatstring) {
        SimpleDateFormat format = new SimpleDateFormat(formatstring);
        Date date = null;
        try {
            date = format.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算相差天数
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }

    /**
     * 计算相差天数
     */
    public static int differentDaysByMillisecondCustom(Date date1, Date date2) {
        return (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
         long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
         long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟" + sec + "秒";
    }

    /**
     * 计算两个时间差(秒)
     * @return
     */
    public static String getDatePoorSec(Date endDate, Date nowDate){
        // 获取两个日期对象相减得到的毫秒数差值
        long differenceInMillis = Math.abs(endDate.getTime() - nowDate.getTime());
        // 将毫秒转换成秒
        long seconds = TimeUnit.MILLISECONDS.toSeconds(differenceInMillis);
        return seconds + " 秒";
    }

    /**
     * 获取前几天的日期，根据day的值
     *
     * @param day
     * @return
     */
    public static Date getDaysBefore(int day, Date date) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.add(Calendar.DAY_OF_MONTH, -day);
        date = now.getTime();
        return date;
    }

    /**
     * 获取月旬 三旬: 上旬1-10日 中旬11-20日 下旬21-31日
     *
     * @param date
     * @return
     */
    public static int getTenDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int i = c.get(Calendar.DAY_OF_MONTH);
        if (i < 11)
            return 1;
        else if (i < 21)
            return 2;
        else
            return 3;
    }

    /**
     * 获取所属旬开始时间
     *
     * @param date
     * @return
     */
    public static Date getTenDayStartTime(Date date) {
        int ten = getTenDay(date);
        try {
            if (ten == 1) {
                return getMonthStartTime(date);
            } else if (ten == 2) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-11");
                return parseDate(df.format(date));
            } else {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-21");
                return parseDate(df.format(date));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取所属旬结束时间
     *
     * @param date
     * @return
     */
    public static Date getTenDayEndTime(Date date) {
        int ten = getTenDay(date);
        try {
            if (ten == 1) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-10");
                return parseDate(df.format(date));
            } else if (ten == 2) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-20");
                return parseDate(df.format(date));
            } else {
                return getMonthEndTime(date);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获得本月的开始时间
     *
     * @return
     */
    public static Date getMonthStartTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        Date dt = null;
        try {
            c.set(Calendar.DATE, 1);
            dt = parseDate(parseDateToStr(YYYY_MM_DD, c.getTime()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dt;
    }

    /**
     * 本月的结束时间
     *
     * @return
     */
    public static Date getMonthEndTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        Date dt = null;
        try {
            c.set(Calendar.DATE, 1);
            c.add(Calendar.MONTH, 1);
            c.add(Calendar.DATE, -1);
            dt = parseDate(parseDateToStr(YYYY_MM_DD, c.getTime()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dt;
    }

    /**
     * 获取所属旬开始时间
     *
     * @param date
     * @return
     */
    public static Date getTenDayStartTime(Date date, int ten) {
        try {
            if (ten == 1) {
                return getMonthStartTime(date);
            } else if (ten == 2) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-11");
                return parseDate(df.format(date));
            } else {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-21");
                return parseDate(df.format(date));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取所属旬结束时间
     *
     * @param date
     * @return
     */
    public static Date getTenDayEndTime(Date date, int ten) {
        try {
            if (ten == 1) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-10");
                return parseDate(df.format(date));
            } else if (ten == 2) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-20");
                return parseDate(df.format(date));
            } else {
                return getMonthEndTime(date);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取上个月月份
     *
     * @return
     */
    public static final String getLastMonth(Date date, String format, int num) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();
        // 设置为当前时间
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, num);
        // 设置为上一个月
        //calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
        date = calendar.getTime();
        return sdf.format(date);
    }

    /**
     * 根据指定日期获取上月日期 YYYY_MM
     *
     * @param time
     * @return
     */
    public static String getLastDate(String time, int num) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM);
        Date date;
        try {
            date = sdf.parse(time);
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.MONTH, num);
            return sdf.format(cal.getTime());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 验证字符串是否为指定日期格式
     *
     * @param oriDateStr 待验证字符串
     * @param pattern    日期字符串格式, 例如 "yyyy-MM-dd"
     * @return 有效性结果, true 为正确, false 为错误
     */
    public static boolean dateStrIsValid(String oriDateStr, String pattern) {
        if (StringUtils.isBlank(oriDateStr) || StringUtils.isBlank(pattern)) {
            return false;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        try {
            Date date = dateFormat.parse(oriDateStr);
            return oriDateStr.equals(dateFormat.format(date));
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 日期位数补0
     *
     * @param date 传入日期
     * @return
     */
    public static String deteFormat(String date, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        date = date.replaceAll("/", "-");
        Date time = null;
        try {
            time = simpleDateFormat.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);

        // 方法一：
//        int month = calendar.get(Calendar.MONTH) + 1;
//        int day = calendar.get(Calendar.DAY_OF_MONTH);
//        System.out.printf("当前月份：%s，当前几号：%s%n", month, day);
//        System.out.printf("当前月份：%s，当前几号：%s%n", month >= 10 ? month : "0" + month, day >= 10 ? day : "0" + day);
        // 方法二：
        // StringUtils.leftPad() 左侧补齐 第一个参数：原始字符串，第二个参数：字符串的长度，第三个是补充的字符串
        String normalizeMonth = StringUtils.leftPad(String.valueOf(calendar.get(Calendar.MONTH) + 1), 2, '0');
        String normalizeDay = StringUtils.leftPad(String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)), 2, '0');
        System.out.printf("当前月份：%s，当前几号：%s%n", normalizeMonth, normalizeDay);

        return calendar.get(Calendar.YEAR) + "-" + normalizeMonth + "-" + normalizeDay;
    }

    /**
     * 数据库查询出来的统计数据有时候日期是不连续的.
     * 但是前端展示要补全缺失的日期.
     * 此方法返回一个给定日期期间的所有日期字符串列表.
     * 具体在业务逻辑中去判断补全.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param Pattern   日期格式
     * @return
     */
    public static List<String> completionDate(String startDate, String endDate, String pattern) {
        String hms = " 00:00:00";
        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern + " HH:mm:ss");
        LocalDateTime startTime = LocalDateTime.parse(deteFormat(startDate, pattern) + hms, df);
        LocalDateTime endTime = LocalDateTime.parse(deteFormat(endDate, pattern) + hms, df);
        // 日期格式化
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        List<String> dateList = new ArrayList<>();
        // 遍历给定的日期期间的每一天
        for (int i = 0; !Duration.between(startTime.plusDays(i), endTime).isNegative(); i++) {
            //添加日期
            dateList.add(startTime.plusDays(i).format(formatter));
        }
        return dateList;
    }

    public static String lastDay(String monthDay) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date sDate = null;
        try {
            sDate = sdf.parse(monthDay);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        Format f = new SimpleDateFormat("yyyy-MM-dd");

        Calendar c = Calendar.getInstance();
        c.setTime(sDate);
        c.add(Calendar.DAY_OF_MONTH, 1);//利用Calendar 实现 Date日期+1天

        sDate = c.getTime();

        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        monthDay = sdf1.format(sDate);
        return monthDay;
    }


//    public static void main(String[] args) {
//        List<String> deteList = DateUtil.completionDate("2023-4-21", "2023/05-2", "yyyy-MM-dd");
//        // [2023-04-21, 2023-04-22, 2023-04-23, 2023-04-24, 2023-04-25, 2023-04-26, 2023-04-27, 2023-04-28, 2023-04-29, 2023-04-30, 2023-05-01, 2023-05-02]
//        System.out.println(deteList);
//    }
}
